/*
 * @Author: 我想吃余 483766615@qq.com
 * @Date: 2025-11-15 13:36:18
 * @LastEditors: 我想吃余 483766615@qq.com
 * @LastEditTime: 2025-11-15 18:02:36
 * @FilePath: /code/oscode/sem_cp/RingQueue.hpp
 * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
 */
#pragma once

#include <iostream>
#include <pthread.h>
#include <semaphore.h>
#include <vector>

static const int defaultcap = 10;

template<class T>
class ringqueue
{
public:
    void P(sem_t &sem)
    {
        sem_wait(&sem);
    }
    void V(sem_t &sem)
    {
        sem_post(&sem);
    }
    void Lock(pthread_mutex_t &mutex)
    {
        pthread_mutex_lock(&mutex);
    }
    void UnLock(pthread_mutex_t &mutex)
    {
        pthread_mutex_unlock(&mutex);
    }
public:
    ringqueue(int cap = defaultcap)
        :_ringqueue(cap)
        ,_cap(cap)
        ,_c_index(0)
        ,_p_index(0)
    {
        sem_init(&_c_sem, 0, 0);
        sem_init(&_p_sem, 0, cap);
        pthread_mutex_init(&_c_mutex, nullptr);
        pthread_mutex_init(&_p_mutex, nullptr);
    }

     
    void push(const T &in)
    {
        P(_p_sem);//申请一份空间资源，空间资源--，若无空间资源可用，线程挂起等待
        Lock(_p_mutex);// 为什么在P操作后再加锁？？P操作本身是原子性的，没必要放在临界区中。
                       // 而且临界区中的代码是不可被并发执行的，临界区越大，程序效率越低，临界区越小越好。先预定再排队
        //生产
        _ringqueue[_p_index] = in;
        //下标位置后移，并维持环形队列特征
        _p_index++;
        _p_index %= _cap;
        
        UnLock(_p_mutex);
        V(_c_sem);//释放一份空间资源，数据资源++
    }

    void pop(T *out)
    {
        P(_c_sem);
        Lock(_c_mutex);
        //消费
        *out = _ringqueue[_c_index];
        //下标位置后移，并维持环形队列特征
        _c_index++;
        _c_index %= _cap;
        UnLock(_c_mutex);
        V(_p_sem);
    }

    ~ringqueue()
    {
        sem_destroy(&_c_sem);
        sem_destroy(&_p_sem);
        pthread_mutex_destroy(&_c_mutex);
        pthread_mutex_destroy(&_p_mutex);
    }
private:
    std::vector<T> _ringqueue;  // 环形队列
    int _cap;                   // 环形队列容量

    int _c_index;               // 消费者下标
    int _p_index;               // 生产者下标

    sem_t _c_sem;               // 消费者关注剩余的数据资源
    sem_t _p_sem;               // 生产者关注剩余的空间资源

    pthread_mutex_t _c_mutex;   // 维护消费者之间的互斥
    pthread_mutex_t _p_mutex;   // 维护生产者之间的互斥
};